// 接口 结构体
interface IPerson{
    readonly id:number, // 约束
    name:string,
    age:number,
    sex?:string //可有可无
}

// 函数类型


// 类类型 noImplicitAny:false 加入配置项处理掉爆红问题
interface ISwim {
    swim()
}

interface Ifly {
    fly()
}
// 接口与接口之间叫继承
interface ImyFw extends Ifly,ISwim{}
// 类与接口之间叫实现（使用implements）
class IMYTest implements ImyFw{
    swim() {
        console.log('飞')
    }
    fly() {
        console.log('有用')
    }
}

class Person{
    // 定义属性
    name:string
    protected age:number // 只能在person和子类调用 外部不可
    private gender:string // 只能在person内使用
    
    constructor(name:string = 'test', age:number = 16, gender:string="mv"){
        this.name = name
        this.age = age
        this.gender = gender
    }
    sayHi(str:string){
        console.log(`${str}`)
    }
}

class student extends Person{
    constructor(name:string,age:number,gender:string){
        super(name,age,gender) // 调用父类的constructor
    }
    sayHi(): void {
        console.log('子类')
        super.sayHi('饿啊') // 调用父类的方法 甚至重写
    }
}

// 多态  父类型的引用指向了子类型的对象 不同类型的对象针对相同的方法 产生了不同的行为


// 存取器 通过get set来保护对象中的原始数据 代理拦截器

class GetTest{
    firstName:string
    lastName:string
    constructor(firstName:string, lastName:string){
        this.firstName = firstName
        this.lastName = lastName
    }
    get fullName(){
        return this.firstName + '_' +  this.lastName
    }

    set fullName(val){
        let names = val.split('_')
    }
}

// 静态属性 static 构造函数不能通过static创建
class staticTest{
    static name1:string = '静态属性 对象作用域的普通变量的属性'
    name:string
    constructor(name:string){
        this.name = name
    }
}

// 抽象类 抽象类只能被继承 继承的子类必须去实现抽象方法
// 抽象类的最终目的是为子类服务 定一个大的框架

abstract class  Animal {
    // 抽象方法 不能有具体实现
    abstract eat()
    // 实例方法
    run(){
        console.log('都是跳着跑')
    }
    constructor(parameters) {
        
    }
}

// 函数类 可选参数和默认参数

function getFullName(firstName:string = 'haha',lastName?:string):string{
    if(lastName){
        return firstName + '-'+ lastName;
    }else{
        return firstName
    }
}

// 剩余参数 rest参数会解析成数组
function showMsgn(str:string,...args:string[]){
    console.log(str)
    console.log(args)
}
// 函数重载 名字相同 涉及的参数不同
/*
function add(x:string,y:string):string
function add(x:number,y:number):number
function add(x:string|number,y:string|number):string|number{
    if(typeof x === 'string' && typeof y === 'string'){
        return x + y
    }else if(typeof x === 'number' && typeof y === 'number'){
        return x + y
    }
}
console.log(add(5,6))
*/
// 泛型 定义函数 接口 类的时候不能预先确定要使用的数据类型 在使用函数 接口 类的时候才能确定数据的类型
// 就是所谓的T
function getArr<T>(val:T,count:number):T[]{
    const arr:Array<T> = []
    for(let i =0; i<count;i++){
        arr.push(val)
    }
    return arr
}
const arr15 = getArr<number>(200,5)
arr15[0].toFixed(3)